package uzpay

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"reflect"
	"sort"
	"strings"
)

func isEmptyValue(v interface{}) bool {
	// Check for nil or zero-value equivalent for the type of v.
	switch v.(type) {
	case string:
		return v == ""
	case nil:
		return true
	default:
		return reflect.ValueOf(v).IsZero()
	}
}

func GenerateSignature(params map[string]any, secret string) (string, error) {
	var sortedKeys []string
	for k := range params {
		sortedKeys = append(sortedKeys, k)
	}
	sort.Strings(sortedKeys)

	var sortedParamStrBuilder strings.Builder
	for _, k := range sortedKeys {
		val := params[k]
		if !isEmptyValue(val) { // Exclude empty or zero-value fields
			sortedParamStrBuilder.WriteString(k)
			sortedParamStrBuilder.WriteString("=")
			sortedParamStrBuilder.WriteString(fmt.Sprintf("%v", val)) // Convert any type to string
			sortedParamStrBuilder.WriteString("&")
		}
	}

	// Remove the last "&"
	sortedParamStr := sortedParamStrBuilder.String()
	sortedParamStr = sortedParamStr[:len(sortedParamStr)-1]

	// Append the secret and create the final string to be hashed
	finalStr := sortedParamStr + "&key=" + secret

	// Generate and lowercase the MD5 hash
	hasher := md5.New()
	_, err := hasher.Write([]byte(finalStr))
	if err != nil {
		return "", err
	}
	signature := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))

	return signature, nil
}
